/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package avl.sv.shared.XML;

import avl.sv.shared.Annotations.Annotation;
import avl.sv.shared.Annotations.AnnotationSet;
import avl.sv.shared.Annotations.Attributes;
import avl.sv.shared.Annotations.ROI;
import avl.sv.shared.Annotations.ROIOval;
import avl.sv.shared.Annotations.ROIPoly;
import avl.sv.shared.Annotations.ROIRectangle;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
 *
 * @author benbryan
 */
public class AnnotationXML_Parser {

    private Annotation annotation;
    private ROI roiTemp;
              
    public Annotation parse(String s) throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance( );
        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
        InputStream is = new ByteArrayInputStream(s.getBytes());
        Document doc = docBuilder.parse(is);
        return parse(doc);             
    }

    public Annotation parse(Document doc) throws ParserConfigurationException, SAXException, IOException {
        doc.getDocumentElement().normalize();
        for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling()) {
            if ("Annotation".equalsIgnoreCase(n.getNodeName())) {
                return parseAnnotationNode((Node) n);
            }
        }
        return null;
    }
        
    public Annotation parseAnnotationNode(Node n) {
        annotation = Annotation.createDefault();
        roiTemp = null;
        NamedNodeMap a = n.getAttributes();
        if (a != null){
            annotation.selected = NamedNodeMapFunc.getBoolean(a, "Selected");
            annotation.visible = NamedNodeMapFunc.getBoolean(a, "Visible");
            annotation.id = NamedNodeMapFunc.getInteger(a, "Id");
            annotation.lineColor = NamedNodeMapFunc.getInteger(a, "LineColor");
            annotation.name = NamedNodeMapFunc.getString(a, "Name");
            annotation.type = NamedNodeMapFunc.getInteger(a, "Type");
        }
        for (Node c = n.getFirstChild(); c != null; c = c.getNextSibling()) {
            if ("Attributes".equalsIgnoreCase(c.getNodeName())) {
                annotation.attributes = new ArrayList<>();
                parseAnnotationAttributes(c);
            }
            if ("Regions".equalsIgnoreCase(c.getNodeName())) {
                parseRegions(c);
            }
        }
        return annotation;
    }

    private void parseAnnotationAttributes(Node n) {
        for (n = n.getFirstChild(); n != null; n = n.getNextSibling()) {
            if ("Attribute".equalsIgnoreCase(n.getNodeName())) {
                Attributes attr = new Attributes();
                attr.id = (NamedNodeMapFunc.getInteger(n.getAttributes(), "Id"));
                attr.name = (NamedNodeMapFunc.getString(n.getAttributes(), "Name"));
                attr.value = (NamedNodeMapFunc.getString(n.getAttributes(),"Value"));
                annotation.attributes.add(attr);
            }
        }
    }

    private void parseRegions(Node n) {
        for (n = n.getFirstChild(); n!=null;n = n.getNextSibling()){
            if ("region".equalsIgnoreCase(n.getNodeName())) {
                if (roiTemp != null) {
                    roiTemp = convertROI(roiTemp);
                    annotation.add(roiTemp);
                }
                NamedNodeMap a = n.getAttributes();
            	roiTemp = ROIPoly.getDefault();
                roiTemp.selected = NamedNodeMapFunc.getBoolean(a,"Selected");
                roiTemp.analyze = NamedNodeMapFunc.getBoolean(a,"Analyze");
                roiTemp.id = NamedNodeMapFunc.getInteger(a, "Id");
                roiTemp.negativeROA = NamedNodeMapFunc.getBoolean(a, "NegativeROA");
                roiTemp.text = NamedNodeMapFunc.getString(a, "Text");
                roiTemp.displayId = NamedNodeMapFunc.getInteger(a, "DisplayId");
                parseRegion(n);
            }
        }
        if (roiTemp != null) {
            roiTemp = convertROI(roiTemp);
            annotation.add(roiTemp);
        }
    }
    
    private ROI convertROI(ROI in){
        Polygon poly = in.getPolygon();
        if (poly.npoints != 4){
            return in;
        }
        Area area = new Area(poly);
        Rectangle rect = poly.getBounds();
        if (area.isRectangular()){
            ROIRectangle roir = new ROIRectangle(rect.x, rect.y, rect.width, rect.height);
            copyParams(in, roir);
            return roir;
        } else {
            ROIOval roio = new ROIOval((int)rect.getCenterX(), (int)rect.getCenterY(), rect.width, rect.height);
            copyParams(in, roio);
            return roio;
        }
    }

    private void copyParams(ROI from, ROI to) {
        to.analyze = from.analyze;
        to.attributes = from.attributes;
        to.displayId = from.displayId;
        to.highlighted = from.highlighted;
        to.id = from.id;
        to.negativeROA = from.negativeROA;
        to.selected = from.selected;
        to.selectedPoints = from.selectedPoints;
        to.text = from.text;
    }
    
    private void parseRegionAttributes(Node n) {
        for (n = n.getFirstChild(); n != null; n = n.getNextSibling()) {
            if ("Attribute".equalsIgnoreCase(n.getNodeName())) {
                Attributes attr = new Attributes();
                attr.id = (NamedNodeMapFunc.getInteger(n.getAttributes(), "Id"));
                attr.name = (NamedNodeMapFunc.getString(n.getAttributes(), "Name"));
                attr.value = (NamedNodeMapFunc.getString(n.getAttributes(),"Value"));
                roiTemp.attributes.add(attr);
            }
        }
    }    
    
    private void parseRegion(Node n) {
        for (n = n.getFirstChild(); n!=null;n = n.getNextSibling()){
            if ("Attributes".equalsIgnoreCase(n.getNodeName())) {
                parseRegionAttributes(n);
            }
            if ("Vertices".equalsIgnoreCase(n.getNodeName())) {
                parseVertices(n);
            }
        }
    }
     
    private void parseVertices(Node n) {
        for (n = n.getFirstChild(); n!=null;n = n.getNextSibling()){
            if ("Vertex".equalsIgnoreCase(n.getNodeName())) {
                double x = 0, y = 0;
                try {
                    x = NamedNodeMapFunc.getDouble(n.getAttributes(),"X");
                    y = NamedNodeMapFunc.getDouble(n.getAttributes(),"Y");
                } finally {
                    roiTemp.addPoint(x, y);
                }
            }
        }
    }
    
}
